package com.moorror.codegenvel.db.mysql.utils;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.moorror.codegenvel.common.sql.SqlTableColumnDesc;
import com.moorror.codegenvel.common.sql.SqlTableDesc;
import com.moorror.codegenvel.utils.JacksonUtils;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

import java.sql.*;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

/**
 * @Author jiyanghuang
 * @Date 2025/10/25 09:13
 */
public class HikaricpUtils {
    // 连接超时时间
    private static final long connectionTimeout = 3000;
    // 配置当前的数据库是否为只读状态
    private static final boolean readOnly = false;
    // 空闲连接超时时间
    private static final long idleTimeout = 6000;
    // 连接最大存活时间
    private static final long maxLifetime = 60000;
    // 最大连接数
    private static final int maxPoolSize = 20;
    // 最小空闲连接，默认值10，小于0或大于maximum-pool-size，都会重置为 maximum-pool-size。
    private static final int minIdle = 1; //

    private static Map<String, HikariDataSource> dataSourceMap = Maps.newLinkedHashMap();

    public static HikariDataSource buildHikariDataSource(String driver, String url, String username, String password) {
        HikariDataSource hikariDataSource = dataSourceMap.get(url);
        if (null == hikariDataSource) {
            synchronized (HikaricpUtils.class) {
                hikariDataSource = dataSourceMap.get(url);
                if (null == hikariDataSource) {
                    HikariConfig config = new HikariConfig();
                    config.setPoolName(String.format("Hikari pool name: %s", url));
                    config.setDriverClassName(driver);
                    config.setJdbcUrl(url);
                    config.setUsername(username);
                    config.setPassword(password);

                    config.setConnectionTimeout(connectionTimeout);
                    config.setReadOnly(readOnly);
                    config.setIdleTimeout(idleTimeout);
                    config.setMaxLifetime(maxLifetime);
                    config.setMaximumPoolSize(maxPoolSize);
                    config.setMinimumIdle(minIdle);

                    // 其它连接池配置参数可根据需要设置
                    hikariDataSource = new HikariDataSource(config);
                    dataSourceMap.put(url, hikariDataSource);
                }
            }
        }
        return hikariDataSource;
    }

    public static <T> T mysqlInvoke(String url, String username, String password, Function<Connection, T> invoke) {
        HikariDataSource hikariDataSource = buildHikariDataSource("com.mysql.cj.jdbc.Driver", url, username, password);
        Connection connection = null;
        try {
            connection = hikariDataSource.getConnection();
            return invoke.apply(connection);
        } catch (Exception ex) {
            if (null != connection) {
                try {
                    connection.close();
                } catch (Exception exx) {
                    exx.printStackTrace();
                }
            }
        }
        return null;
    }

    public static List<SqlTableDesc> tables(Connection conn) {
        List<SqlTableDesc> re = Lists.newArrayList();
        try {
            DatabaseMetaData dbmd = conn.getMetaData();
            ResultSet rs = dbmd.getTables(null, null, "%", new String[]{"TABLE"}); // 获取所有表，null代表当前连接的catalog（即数据库）和schema（模式），"%代表所有表，"TABLE"指定只获取表而非视图等。
            while (rs.next()) {
                String tableName = rs.getString("TABLE_NAME"); // 获取表名
                re.add(SqlTableDesc.of(tableName, rs.getString("REMARKS")));
            }
            return re;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return re;
    }

    public static List<SqlTableColumnDesc> tableColumns(Connection conn, String tableName) {
        List<SqlTableColumnDesc> re = Lists.newArrayList();
        try {
            DatabaseMetaData dbmd = conn.getMetaData();
            ResultSet rs = dbmd.getColumns(null, null, tableName, null);
//            ResultSet rs = dbmd.getTables(null, null, "%", new String[]{"TABLE"}); // 获取所有表，null代表当前连接的catalog（即数据库）和schema（模式），"%代表所有表，"TABLE"指定只获取表而非视图等。
            while (rs.next()) {
                SqlTableColumnDesc columnDesc = new SqlTableColumnDesc();
                String columnName = rs.getString("COLUMN_NAME"); // 获取表名
                columnDesc.setColumnName(columnName);
                columnDesc.setTypeName(rs.getString("TYPE_NAME"));
                columnDesc.setDataType(rs.getString("DATA_TYPE"));
                columnDesc.setComment(rs.getString("REMARKS"));
                re.add(columnDesc);
            }
            return re;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return re;
    }

    public static Map<String, String> queryColumn(Connection conn, String sql, String... fieldNames) {
        Map<String, String> re = Maps.newLinkedHashMap();
        try {
            Statement statement = conn.createStatement();
            ResultSet rs = statement.executeQuery(sql);
            while (rs.next()) {
                for (String fieldName : fieldNames) {
                    re.put(fieldName, rs.getString(fieldName));
                }
            }
            return re;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return re;
    }

    public static boolean executeUpdate(Connection conn, String sql, List<Object> values) {
        try {
            PreparedStatement statement = conn.prepareStatement(sql);
            int index = 0;
            for (Object object : values) {
                index++;
                if (object instanceof Integer) {
                    statement.setInt(index, (int) object);
                } else if (object instanceof Double) {
                    statement.setDouble(index, (Double) object);
                } else {
                    statement.setString(index, (String) object);
                }
            }
            int re = statement.executeUpdate();
            return re > 0;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return false;
    }


    public static List<SqlTableDesc> tables(String url, String username, String password) {
        return mysqlInvoke(url, username, password, HikaricpUtils::tables);
    }

    public static List<SqlTableColumnDesc> tableColumns(String url, String username, String password, String tableName) {
        return mysqlInvoke(url, username, password, (connection -> {
            return tableColumns(connection, tableName);
        }));
    }

    public static Map<String, String> queryColumnInvoke(String url, String username, String password, String sql, String... fieldNames) {
        return mysqlInvoke(url, username, password, (connection -> {
            return queryColumn(connection, sql, fieldNames);
        }));
    }

    public static boolean executeUpdate(String url, String username, String password, String sql, List<Object> values) {
        return mysqlInvoke(url, username, password, (connection -> {
            return executeUpdate(connection, sql, values);
        }));
    }


    public static void main(String[] args) throws Exception {
        try {
            String url = "jdbc:mysql://localhost:3306/trade_single_sys?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true"; // 注意这里不指定具体数据库名，因为我们将在运行时获取数据库列表。
            String user = "root";
            String password = "root123456";
            List<SqlTableDesc> tables = mysqlInvoke(url, user, password, HikaricpUtils::tables);
            System.out.println(JacksonUtils.toJSONString(tables));
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}
